這篇文章要來實際使用一下 Azure Cosmos DB
的 Cassandra API
。
如果已經安裝了 cqlsh
可以直接用如下方式連線:
set SSL_VERSION=TLSv1_2
set SSL_VALIDATE=false
cqlsh yichengcosmos.cassandra.cosmosdb.azure.com 10350 -u yichengcosmos -p <填上 PRIMARY PASSWORD> --ssl
首先我們一樣先使用看看官方提供的範例:
git clone https://github.com/Azure-Samples/azure-cosmos-db-cassandra-nodejs-getting-started.git && cd azure-cosmos-db-cassandra-nodejs-getting-started && npm install
然後到 portal 把 Connection string
記錄下來。
填入 config.js
中
config.contactPoint
記得在後面加上 PORT 號
因為在連線需要填入 sslOptions
所以要一張憑證,首先在此處官方提供的連結下載憑證:https://cacert.omniroot.com/bc2025.crt
然後把他移動到專案目錄下,並把檔案副檔名改為 cer
。
mkdir ./cert && mv ~/Downloads/bc2025.crt ./cert/bc2025.cer
最後更改一下 uprofile.js
的 cert
路徑。
之後執行程式: node uprofile.js
。
這時各位可能會產生
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
的錯誤,然後十分困惑。
不過不要緊,我們不要用官方的,自己來產生一張 X509
證書即可:
openssl req -newkey rsa:2048 -new -nodes -keyout key.pem -out csr.pem
輸入後填上相關資訊,也可以都按 Enter
然後從 pem
轉為 crt
openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out server.crt
最後再把 server.crt
改名字為 server.cer
即可
mv server.crt server.cer
之後執行範例程式:
node uprofile.js
這時會出現
{ TypeError: Cannot read property 'type' of undefined
的錯誤,因為 Azure 目前的官方範例有點問題,在batch
批量Insert
的時候params
多了一個參數。
這時把最後面的日期參數移除後再次執行:
沒想到又出現如下錯誤:
{ ResponseError: Logged batches are not supported by the service yet. Please use unlogged batches instead.
logged batches
代表該 batch 執行是原子性的,而cosmos DB
目前不支援,只能用unlogged batched
。但是cosmos DB
通常會有多個partition
所以如果使用unlogged batched
為anti-pattern
的操作,可參考:https://stackoverflow.com/a/49471102
在 Azure 解決這個範例錯誤與 batch 的問題之前我們先將它改為一般的Insert
。
我們接著不使用官方範例,把 uprofile.js
直接改為以下,自己來操作看看。
const cassandra = require('cassandra-driver');
const tls = require("tls");
const fs = require("fs");
const config = require("./config");
const ssl_option = {
cert: fs.readFileSync("./cert/server.cer"),
secureProtocol: "TLSv1_2_method"
};
const authProviderLocalCassandra =
new cassandra.auth.PlainTextAuthProvider(config.username, config.password);
const client = new cassandra.Client({
contactPoints: [config.contactPoint],
authProvider: authProviderLocalCassandra,
sslOptions:ssl_option
});
client.connect();
const query = "CREATE KEYSPACE IF NOT EXISTS Fruits WITH replication = {\'class\': \'NetworkTopologyStrategy\', \'datacenter\' : \'1\' }";
client.execute(query)
.then(result => {
console.log(result);
client.shutdown();
})
.catch(err => console.log(err));
const cassandra = require("cassandra-driver");
const tls = require("tls");
const fs = require("fs");
const config = require("./config");
const ssl_option = {
cert: fs.readFileSync("./cert/server.cer"),
secureProtocol: "TLSv1_2_method"
};
const authProviderLocalCassandra = new cassandra.auth.PlainTextAuthProvider(
config.username,
config.password
);
const client = new cassandra.Client({
contactPoints: [config.contactPoint],
authProvider: authProviderLocalCassandra,
sslOptions: ssl_option
});
client.connect()
.then(function () {
const query = "CREATE TABLE IF NOT EXISTS Fruits.banana " +
"(_id int PRIMARY KEY, price int, name text)";
return client.execute(query);
})
.catch(function (err) {
console.error('There was an error', err);
return client.shutdown();
});
const cassandra = require("cassandra-driver");
const tls = require("tls");
const fs = require("fs");
const config = require("./config");
const ssl_option = {
cert: fs.readFileSync("./cert/server.cer"),
secureProtocol: "TLSv1_2_method"
};
const authProviderLocalCassandra = new cassandra.auth.PlainTextAuthProvider(
config.username,
config.password
);
const client = new cassandra.Client({
contactPoints: [config.contactPoint],
authProvider: authProviderLocalCassandra,
sslOptions: ssl_option
});
client.connect()
.then(function () {
console.log('Inserting');
const query = 'INSERT INTO Fruits.banana (_id, price, name) VALUES (?, ?, ?)';
return client.execute(query, [1, 100, "Super banana"], { prepare: true});
})
.then(function () {
const query = 'SELECT price, name FROM Fruits.banana WHERE _id = ?';
return client.execute(query, [1], { prepare: true });
})
.then(function (result) {
const row = result.first();
console.log('Retrieved row: %j', row);
return client.shutdown();
})
.catch(function (err) {
console.error('There was an error', err);
return client.shutdown();
});
回到 portal
的 Data explorer
即可看到剛才插入的資料:
有時插入資料後按下 portal 頁面上的重新整理不會有反應,要把網頁重新整理一次才行。
那我們這篇介紹就到這邊為止,有興趣的朋友可以稍微玩一下。